<?php
/**
 * Created by PhpStorm.
 * User: wenqiang.yq@gmail.com
 * Date: 16-3-2
 * Time: 上午10:22
 */

namespace ElasticSearch;


class EsSearch extends EsBase
{
    const TPL_QUERY_BASE = "query_base";
    /**
     * 查询返回的原始内容体
     * @var string
     */
    private $_hits = "";

    /**
     * 整个请求花费的毫秒数
     * @var string
     */
    private $_took = "";

    /**
     * 参与查询的分片信息
     * @var string
     */
    private $_shards = "";

    /**
     * 是否超时
     * @var string
     */
    private $_timeout = "";

    /**
     * 错误信息
     * @var string
     */
    private $_error = "";

    /**
     * 使用模板文件进行查询
     * @param $templateName
     * @param array $data
     * @return array|EsSearch
     */
    public function template($templateName, $data = array())
    {
        if (is_file($templateName) && file_exists($templateName)) {
            $file = $templateName;
        } else {
            $file = ES_JSON_FOLD . "template" . DIRECTORY_SEPARATOR . "tpl_" . $templateName . ".json";
        }
        if (!file_exists($file)) {
            return array();
        }
        $queryBody = file_get_contents($file);
        foreach ($data as $key => $value) {
            $pattern = '/\{\$' . $key . '\}/';
            if (is_array($value)) {
                $value = "[" . implode(",", $value) . "]";
            }
            $queryBody = preg_replace($pattern, $value, $queryBody);
        }
        return $this->bodyQuery($queryBody);
    }

    /**
     * 请求体查询
     * @param string $queryBody
     * @param string $index
     * @param string $type
     * @param int $limit
     * @param int $start
     * @return $this
     */
    public function bodyQuery($queryBody = "", $index = "", $type = "", $limit = 100, $start = 0)
    {
        list($index, $type) = $this->info($index, $type);
        $check = $this->checkQueryStr($queryBody, $index, $type);
        if (!$check['status']) {
            $this->_error = $check;
            return $this;
        }
        $uri = $this->queryUri($index, $type);
        if (!$queryBody) {
            $queryBody = array(
                "query" => array(
                    "match_all" => array()
                )
            );
        }
        !is_array($queryBody) && $queryBody = json_decode($queryBody, 1);
        $queryBody["from"] = $start;
        $queryBody["size"] = $limit;
        $queryBody = json_encode($queryBody);
        $result = EsHttp::post($uri, $queryBody);
        $this->_took = $result["took"];
        $this->_timeout = $result["timed_out"];
        $this->_shards = $result["_shards"];
        $this->_hits = $result["hits"];
        return $this;
    }

    /**
     * 字符串参数查询
     * @param $index
     * @param $type
     * @param string $queryStr
     * @param int $limit
     * @param int $start
     * @return mixed|string
     */
    public function paramsQuery($index, $type, $queryStr = "", $limit = 10, $start = 0)
    {
        $uri = $this->queryUri($index, $type);
        $params = $this->queryParams(array(
            "size" => $limit,
            "from" => $start,
            "q" => $queryStr
        ));
        $uri .= "?" . $params;
        $result = EsHttp::get($uri);
        $this->_took = $result["took"];
        $this->_timeout = $result["timed_out"];
        $this->_shards = $result["_shards"];
        $this->_hits = $result["hits"];
        return $this;
    }

    /**
     * 查询结果
     * @param bool $score 是否需要权重值
     * @return array
     */
    public function result($score = false)
    {
        $result = [];
        if (!$this->_error) {
            foreach ($this->_hits['hits'] as $hit) {
                $score && $hit['_source']["__score__"] = $hit['_score'];
                $result[$hit['_id']] = $hit['_source'];
            }
        }
        return $result;
    }

    /**
     * 魔术方法,获取参数
     * @param $name
     * @return mixed
     */
    public function __get($name)
    {
        $name = "_" . $name;
        return $this->$name;
    }

    /**
     * 构建查询参数
     * @param array $params
     * @return string
     */
    public function queryParams($params = array())
    {
        $searchParams = array();
        foreach ($params as $key => $param) {
            if ($param) {
                $searchParams[] = "{$key}={$param}";
            }
        }
        return implode("&", $searchParams);
    }

    /**
     * 构建查询的uri
     * @param string $index
     * @param string $type
     * @return string
     */
    public function queryUri($index = "", $type = "")
    {
        !$index && $index = "_all";
        $uri = EsTools::baseUri($this->hosts, $index, $type);
        $uri .= "/_search";
        return $uri;
    }


    /**
     * 验证query是否有效
     * @param $queryStr
     * @param string $index
     * @param string $type
     * @param string $hosts
     * @return mixed|string
     */
    public function checkQueryStr($queryStr, $index = "", $type = "", $hosts = "")
    {
        !$hosts && $hosts = $this->hosts;
        $uri = EsTools::baseUri($hosts, $index, $type);
        $uri .= "/_validate/query";
        if (is_array($queryStr)) {
            $queryStr = json_encode($queryStr);
        }
        $result = EsHttp::get($uri, $queryStr);
        $valid = intval($result["valid"]);
        $return["status"] = 1;
        if (!$valid) {
            $return["status"] = 0;
            $uri .= "?explain";
            $result = EsHttp::get($uri, $queryStr);
            foreach ($result["explanations"] as $explain) {
                if (!$explain["valid"]) {
                    $return["msg"][] = $explain["error"];
                }
            }
        }
        return $return;
    }

    /**
     * 查看文本是如何被分析,以用来进行查询的
     * @param string $text
     * @param string $analyzer
     * @return mixed|string
     */
    public function analyze($text = "", $analyzer = "standard")
    {
        $uri = EsTools::specialUri($this->hosts, "_analyze");
        $uri .= "?analyzer={$analyzer}";
        $result = EsHttp::get($uri, $text);
        return $result;
    }
}